home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Amiga
/
World of Amiga.iso
/
archive
/
music
/
oplay1231.lha
/
src
/
oplay.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-31
|
16KB
|
618 lines
/*
* OmniPlay, v1.23
* by David Champion
*
* command parser & playroutine
* 19 Nov 92
*/
#include <exec/types.h>
#include <exec/exec.h>
#include <graphics/gfxbase.h>
#include <dos/dos.h>
#include <devices/audio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "oplay.h"
#include "forms.h"
extern struct library *DOSBase;
/*
* libraries/mathffp.h from clib/alib_protos.h prototypes abs(),
* which conflicts with stdlib.h
*/
#ifndef LIBRARIES_MATHFFP_H
#define LIBRARIES_MATHFFP_H 1
#endif /* LIBRARIES_MATHFFP_H */
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <pragmas/exec_lib.h>
#include <clib/dos_protos.h>
#include <pragmas/dos_lib.h>
#include <pragmas/powerpacker.h>
/* prototypes */
//void main(int, char **);
void parsecli(int, char **);
void play(char *);
void info(char *, char *);
UWORD toperiod(const UWORD);
struct IOAudio *GetIOB(ULONG);
struct IOAudio *CopyIOB(struct IOAudio *);
void FreeIOB(struct IOAudio *);
void FreeCopy(struct IOAudio *);
ULONG LoadIOB(BPTR, struct IOAudio *, ULONG, char *);
void clean(int);
void Usage(int);
int TokenizeString(char *, char **);
extern ULONG readfile(char *);
extern void propinfo(char *, char *, ULONG);
extern char *tmpnam(char *);
/* constants */
UBYTE ch_l[4] = {1, 8, 1, 8};
UBYTE ch_r[4] = {2, 4, 2, 4};
UBYTE ch_e[4] = {1, 4, 2, 8};
UBYTE ch_s[4] = {3, 5, 10, 12};
/* globals */
char version[] = "$VER: OmniPlay 1.231 (31.1.93)";
BPTR fp;
BPTR writefp;
UBYTE *chan = ch_e;
ULONG len;
char utype = AUTO;
UWORD uvol = 0;
UWORD urate = 0;
UWORD vol = 0;
UWORD rate = 0;
ULONG ubufsiz = 4000;
ULONG bufsiz;
BOOL oneshot = 0;
char *myname;
char cvmode = CV_NONE;
BOOL showprops = 1;
UWORD displaymode = NTSC;
LONG oldpri;
BOOL genulawtab = 0;
BOOL showmax = 0;
int max;
int amplify = 1;
//int Amplify = 1;
BOOL fileinfo = 0;
char *writefn;
int totallen;
FILE *mystdout;
int RptCycles = 1;
signed char logs[256];
struct Library *PPBase;
extern char pptmp[];
extern BOOL ppuse;
void main(int ac, char **av)
{
struct GfxBase *GfxBase;
char env[CMDMAXLEN+1];
int envc;
char *envv[CMDMAXLEN+1];
char *envl;
oldpri = SetTaskPri((struct Task *)FindTask(NULL), -1);
if ( !ac ) exit(0); /* No WB usage */
myname=av[0];
mystdout = stdout;
if ( GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L) ) {
displaymode = GfxBase->DisplayFlags; /* PAL or NTSC? */
CloseLibrary((struct Library *)GfxBase);
}
else info("Can't get display mode; assuming NTSC", myname);
/* get pplib */
PPBase = (struct Library *)OpenLibrary("powerpacker.library", 33L);
if ( ac == 1 ) {
Usage(0);
clean(0);
}
shift;
if ( envl=getenv("OMNIPLAY") ) {
strncpy(env, envl, CMDMAXLEN);
if ( (envc=TokenizeString(env, envv)) != 0 ) parsecli(envc, envv);
}
parsecli(ac, av);
clean(0);
}
void parsecli(int ac, char **av)
{
char option;
char *optarg;
LONG pri;
while ( ac > 0 ) {
if ( USERBREAK ) {
info("User break", myname);
break;
}
if ( av[0][0] == '-' ) {
option = av[0][1];
if ( strlen(av[0]) == 2 ) {
shift;
optarg=av[0];
}
else optarg=&av[0][2];
switch ( option ) {
case 'h':
Usage(1);
break;
case 'v':
uvol = atoi(optarg);
break;
case 'r':
urate = atoi(optarg);
break;
case 'c':
if ( optarg[0] == 'l' ) chan = ch_l;
else if ( optarg[0] == 'r' ) chan = ch_r;
else if ( optarg[0] == 'e' ) chan = ch_e;
else if ( optarg[0] == 's' ) chan = ch_e;
else {
info("Unknown channel", optarg);
clean(10);
}
break;
case 'o':
if ( (strcmp(optarg, "0")) && (strcmp(optarg, "1")) ) info("Bad usage of -o option", av[0]);
else oneshot = (BOOL)atoi(optarg);
break;
case 'b':
ubufsiz = atoi(optarg);
break;
case 'p':
pri = atoi(optarg);
if ( ( pri < -10 ) || (pri > 10) ) {
info("Can't change priority out of {-10, 10}", av[0]);
break;
}
SetTaskPri((struct Task *)FindTask(NULL), pri);
break;
case 'w':
Delay(atoi(optarg));
break;
case 's':
if ( (strcmp(optarg, "0")) && (strcmp(optarg, "1")) ) info("Bad usage of -s option", av[0]);
else showprops = (BOOL)atoi(optarg);
break;
case 'd':
if ( !strcmp(optarg, "PAL") ) displaymode = PAL;
else if ( !strcmp(optarg, "NTSC") ) displaymode = NTSC;
else info("Bad usage of -d option", av[0]);
break;
case 'f':
if ( strlen(optarg) != 1 ) {
info("Bad usage of -f option", av[0]);
break;
}
switch( optarg[0] ) {
case 'u':
utype = RAWU;
break;
case 's':
utype = RAWS;
break;
case 'l':
utype = RAWL;
break;
case 'a':
utype = AUTO;
break;
default:
info("Bad usage of -f option", av[0]);
break;
}
break;
case 'g':
if ( (strcmp(optarg, "0")) && (strcmp(optarg, "1")) ) info("Bad usage of -g option", av[0]);
else genulawtab = (BOOL)atoi(optarg);
break;
case 'm':
if ( (strcmp(optarg, "0")) && (strcmp(optarg, "1")) ) info("Bad usage of -m option", av[0]);
else showmax = (BOOL)atoi(optarg);
break;
case 'a':
amplify = atoi(optarg);
break;
// case 'A':
// Amplify = atoi(optarg);
// break;
case 'i':
if ( (strcmp(optarg, "0")) && (strcmp(optarg, "1")) ) info("Bad usage of -i option", av[0]);
else fileinfo = atoi(optarg);
break;
case 'W':
writefn = optarg;
break;
case 'O':
if ( mystdout != stdout ) {
info("Output can be changed only once", av[0]);
break;
}
mystdout = fopen(optarg, "w");
break;
case 'R':
RptCycles = atoi(optarg);
break;
case '-':
{
char tmp[CMDMAXLEN+1];
tmp[0] = '-';
strncpy(&tmp[1], optarg, CMDMAXLEN-1);
play( tmp );
if ( writefn ) writefn = NULL;
if ( ppuse ) {
DeleteFile(pptmp);
ppuse=0;
}
}
break;
default:
info("Unknown option", av[0]);
break;
}
}
else {
play( av[0] );
if ( writefn ) writefn = NULL;
if ( ppuse ) {
DeleteFile(pptmp);
ppuse=0;
}
}
shift;
}
return;
}
void play(char *fn)
{
struct IOAudio *buf1, *buf2;
register ULONG size;
register int b2used=0;
int rptcycles = RptCycles;
ULONG datastart;
int origlen;
if ( showprops ) fprintf(mystdout, "\n"COL3"File : %s"COL1"\n", fn);
if ( writefn ) {
totallen = 40;
if ( !(writefp = (BPTR) Open(writefn, MODE_NEWFILE)) ) {
info("Can't open IFF output", "-W");
writefn = NULL;
}
else Write((BPTR)writefp, "FORM----8SVXVHDR\000\000\000\024++++----++++----++++", 40);
}
if ( (len = readfile(fn)) == 0L ) return;
origlen = len;
datastart = Seek(fp, 0, OFFSET_CURRENT);
// bufsiz = oneshot ? (len/2)+1 : ubufsiz;
bufsiz = oneshot ? len : ubufsiz;
if ( fileinfo ) {
char *style_str[] = {
"8-bit",
"16-bit",
"signed",
"unsigned",
"u-law"
};
fprintf(mystdout, "Rate\t= %d\n", rate);
fprintf(mystdout, "Volume\t= %d\n", vol);
fprintf(mystdout, "Length\t= %d\n", len);
fprintf(mystdout, "Buffers\t= %d\n", bufsiz);
fprintf(mystdout, "Style\t= %s %s\n", style_str[(cvmode&4)>>2], style_str[(cvmode&3)+2]);
}
if ( showmax && (cvmode & CV_ULAW) ) fprintf(mystdout, "Ulaw max= %d.\n", max);
if ( writefn ) {
struct Voice8Header vhdr = {0, 0, 0, 10000, 1, 0, 64<<10};
vhdr.oneShotHiSamples = len;
vhdr.samplesPerSec = rate;
vhdr.volume = vol;
totallen += len;
Seek((BPTR)writefp, 4, OFFSET_BEGINNING);
Write((BPTR)writefp, &totallen, 4);
Seek((BPTR)writefp, 20, OFFSET_BEGINNING);
Write((BPTR)writefp, &vhdr, sizeof(struct Voice8Header));
Seek((BPTR)writefp, 0, OFFSET_END);
Write((BPTR)writefp, "BODY", 4);
Write((BPTR)writefp, &len, 4);
}
fflush(mystdout);
rate = toperiod(rate);
if ( !(buf1 = (struct IOAudio *)GetIOB(bufsiz)) ) {
info("Can't allocate buffer one", fn);
Close((BPTR)fp);
return;
}
buf1->ioa_Period = rate;
buf1->ioa_Volume = vol;
buf1->ioa_Cycles = 1;
if ( len > bufsiz ) {
if ( !(buf2 = (struct IOAudio *)CopyIOB(buf1)) ) {
info("Can't allocate buffer two", fn);
FreeIOB(buf1);
Close((BPTR)fp);
return;
}
}
else buf2 = NULL;
while ( rptcycles-- ) {
do {
if ( USERBREAK ) {
info("User break", fn);
len = 0;
}
if ( len <= 0 ) {
if ( b2used ) WaitIO((struct IORequest *)buf2);
break;
}
size = MIN(len, bufsiz);
if ( !LoadIOB(fp, buf1, size, fn) ) {
if ( b2used ) WaitIO((struct IORequest *)buf2);
break;
}
len -= size;
buf1->ioa_Length = size;
BeginIO((struct IORequest *)buf1);
if ( b2used ) WaitIO((struct IORequest *)buf2);
if ( USERBREAK ) {
info("User break", fn);
len = 0;
}
if ( len <= 0 ) {
WaitIO((struct IORequest *)buf1);
break;
}
size = MIN(len, bufsiz);
if ( !LoadIOB(fp, buf2, size, fn) ) {
WaitIO((struct IORequest *)buf1);
break;
}
b2used++;
len -= size;
buf2->ioa_Length = size;
BeginIO((struct IORequest *)buf2);
WaitIO((struct IORequest *)buf1);
} while ( TRUE );
Seek(fp, datastart, OFFSET_BEGINNING);
len = origlen;
}
FreeIOB(buf1);
if ( buf2 ) FreeCopy(buf2);
Close((BPTR)fp);
if ( writefn ) Close((BPTR)writefp);
return;
}
void info(char *msg, char *offender)
{
fprintf(mystdout, "%s: %s: %s\n", myname, offender, msg);
return;
}
UWORD toperiod(const UWORD sps)
{
if ( displaymode == PAL ) return( (UWORD)((1000000000 / 281)/sps) );
/* not PAL, assume NTSC (GENLOC not an option here... */
else return( (UWORD)((1000000000 / 279)/sps) );
}
struct IOAudio *GetIOB(ULONG size)
{
struct IOAudio *IOB;
void *buf;
struct MsgPort *port;
if ( !(port = (struct MsgPort *)CreatePort("omniplay", 0)) ) return(NULL);
if ( !(buf = (void *)AllocMem(size, MEMF_CHIP)) ) {
DeletePort(port);
return(NULL);
}
if ( !(IOB = (struct IOAudio *)AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC|MEMF_CLEAR)) ) {
DeletePort(port);
FreeMem(buf, size);
return(NULL);
}
IOB->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
IOB->ioa_Request.io_Message.mn_ReplyPort = port;
IOB->ioa_Data = chan;
IOB->ioa_Length = 4;
IOB->ioa_Request.io_Command = ADCMD_ALLOCATE;
OpenDevice("audio.device", 0, (struct IORequest *)IOB, 0);
if ( !IOB->ioa_AllocKey ) {
DeletePort(port);
FreeMem(buf, size);
FreeMem(IOB, sizeof(struct IOAudio));
return(NULL);
}
IOB->ioa_Request.io_Command = CMD_WRITE;
IOB->ioa_Request.io_Flags = ADIOF_PERVOL;
IOB->ioa_Data = buf;
IOB->ioa_Length = size;
return((struct IOAudio *)IOB);
}
struct IOAudio *CopyIOB(struct IOAudio *oldIOB)
{
struct IOAudio *IOB;
void *buf;
if ( !oldIOB ) return(NULL);
if ( !(buf = (void *)AllocMem(oldIOB->ioa_Length, MEMF_CHIP)) ) return(NULL);
if ( !(IOB = (struct IOAudio *)AllocMem(sizeof(struct IOAudio), MEMF_PUBLIC|MEMF_CLEAR)) ) {
FreeMem(buf, oldIOB->ioa_Length);
return(NULL);
}
CopyMem(oldIOB, IOB, sizeof(struct IOAudio));
IOB->ioa_Data = buf;
return((struct IOAudio *)IOB);
}
void FreeIOB(struct IOAudio *IOB)
{
if ( !IOB ) return;
if ( IOB->ioa_Data ) FreeMem((UBYTE *)IOB->ioa_Data, bufsiz);
IOB->ioa_Request.io_Command = ADCMD_FREE;
BeginIO((struct IORequest *)IOB);
WaitIO((struct IORequest *)IOB);
DeletePort(IOB->ioa_Request.io_Message.mn_ReplyPort);
CloseDevice((struct IORequest *)IOB);
FreeMem(IOB, sizeof(struct IOAudio));
return;
}
void FreeCopy(struct IOAudio *IOB)
{
if ( !IOB ) return;
if ( IOB->ioa_Data ) FreeMem((UBYTE *)IOB->ioa_Data, bufsiz);
FreeMem(IOB, sizeof(struct IOAudio));
return;
}
ULONG LoadIOB(BPTR lfp, struct IOAudio *IOB, ULONG size, char *fn)
{
register int i;
register UBYTE *iodata;
//LONG j;
if ( !size ) return(0L);
iodata = IOB->ioa_Data;
if ( cvmode & CV_DOWN ) {
UWORD tmp;
if ( cvmode & CV_BEND ) {
for(i=0; i<size; i++) {
Read((BPTR)lfp, &tmp, 2);
iodata[i] = (UBYTE)(tmp >> 8);
}
// IOB->ioa_Length = size;
}
else if ( cvmode & CV_LEND ) {
for(i=0; i<size; i++) {
Read((BPTR)lfp, &tmp, 2);
iodata[i] = (UBYTE)(tmp & 0xff);
}
// IOB->ioa_Length = size;
}
}
// else IOB->ioa_Length = Read((BPTR)lfp, iodata, size);
else Read((BPTR)lfp, iodata, size);
if ( cvmode & CV_ULAW ) {
for(i=0; i<size; i++) iodata[i] = logs[iodata[i]];
}
if ( cvmode & CV_FLIP ) {
for(i=0; i<size; i++) iodata[i] ^= 0x80;
}
if ( amplify != 1 ) for(i=0; i<size; i++) iodata[i] = (signed char)(iodata[i] * amplify);
// if ( Amplify != 1 ) for(i=0; i<size; i++) {
// j = (LONG)(iodata[i] * Amplify / 100);
// iodata[i] = (signed char)(j<0 ? MIN(j, -128) : MAX(j, 127));
// }
if ( writefn ) Write((BPTR)writefp, iodata, size);
return(IOB->ioa_Length);
}
void clean(int code)
{
if ( mystdout != stdout ) {
fclose(mystdout);
}
SetTaskPri((struct Task *)FindTask(NULL), oldpri);
if ( PPBase ) CloseLibrary((struct Library *)PPBase);
exit(code);
}
void Usage(int degree)
{
fprintf(mystdout, "%s: Usage:\n", &version[6]);
fprintf(mystdout, "%s\t[-h] [-b"COL3"bufsize"COL1"] [-c"COL3"l|r|e"
COL1"] [-r"COL3"rate"COL1"] [-v"COL3"volume"COL1"] [-f"
COL3"a|l|s|u"COL1"]\n", myname);
fprintf(mystdout, "\t[-w"COL3"ticks"COL1"] [-s"COL3"0|1"COL1"] [-p"
COL3"pri"COL1"] [-d"COL3"PAL|NTSC"COL1"] [-g"COL3"0|1"COL1
"] [-m"COL3"0|1"COL1"] [-o"COL3"0|1"COL1"]\n");
fprintf(mystdout, "\t[-O"COL3"filespec"COL1"] [-a"COL3"factor"COL1/*"] [-A"COL3
"factor"COL1*/"] [-W"COL3"filename"COL1"] [--"COL3"file"COL1
"] "COL3"file [...]"COL1"\n\n");
if ( !degree ) fprintf(mystdout, "Use "COL3"oplay -h"COL1" for extended usage information.\n");
if ( degree ) {
fprintf(mystdout, "\t-h:\thelp. This stuff here.\n");
fprintf(mystdout, "\t-b:\tsize of one audio buffer (there are two).\n");
fprintf(mystdout, "\t-c:\tchannel: left, right, or either.\n");
fprintf(mystdout, "\t-r:\toverride sound file's playback rate, in samples per second.\n");
fprintf(mystdout, "\t-v:\toverride sound file's volume. 0 <= volume <= 64.\n");
fprintf(mystdout, "\t-f:\tforce playback as Auto, u-Law, Signed raw, or Unsigned raw.\n");
fprintf(mystdout, "\t-w:\tpause between sounds. One tick is 1/50 second.\n");
fprintf(mystdout, "\t-p:\tset %s's task priority.\n", myname);
fprintf(mystdout, "\t-s:\tshow (1) or don't show (0) optional properties.\n");
fprintf(mystdout, "\t-d:\toverride default electrical standard.\n");
fprintf(mystdout, "\t-g:\tgenerate log tables for ulaw files.\n");
fprintf(mystdout, "\t-m:\tshow maximum encoded value for ulaw files.\n");
fprintf(mystdout, "\t-o:\toneshot; override buffersize, loading whole file at once.\n");
fprintf(mystdout, "\t-O:\tspecify output file or window.\n");
fprintf(mystdout, "\t-a:\tamplify; multiplies loudness by the given integer.\n");
// fprintf(mystdout, "\t-A:\tamplify; multiplies loudness by the given integer (cropped).\n");
fprintf(mystdout, "\t-i:\tdisplay arcane sound information\n");
fprintf(mystdout, "\t-W:\twrite the file as IFF.\n");
fprintf(mystdout, "\t--:\tplay a file whose name begins with '-'.\n\n");
fprintf(mystdout, "Any argument can appear anywhere. Options take effect as processed, after\n");
fprintf(mystdout, "any preceding files have been played. You can use this to readjust OmniPlay's\n");
fprintf(mystdout, "settings on a per-sound basis. To remove rate or volume override, use\n");
fprintf(mystdout, "-r0 or -v0. To remove amplification, use -a1.\n");
}
return;
}
int TokenizeString(char *line, char **av)
{
int ac = 0;
av[ac++] = (char *)strtok(line, " ");
while ( av[ac++] = (char *)strtok(NULL, " ") );
return(--ac);
}